﻿using System;
using System.Runtime.CompilerServices;
using Microsoft.Scripting.Runtime;

namespace Cjc.Calculation.ExpressionEngine.Excel.Runtime.Operations
{
	public static class Int32Ops
	{
        //
        // Conversion methods are required where no implicit conversions are supplied by the underlying DotNet types but are needed 
        // by our semantics.  DefaultBinder.ConvertTo, which we do not override, looks first for an implicit conversion operator, first on
        // the type, then by calling ActionBinder.GetMethod  (ActionBinder is the base class of DefaultBinder).
        // If nothing is found, ConvertTo looks instead for the method ConvertTo<toType>, where <toType> is the type to be be converted to.  
        // ActionBinder.GetMethod reflects on the extension classes (like this one) looking for an implementation. 
        // GetMethod finds the extensions by calling GetExtensionTypes, which ExcelBinder overrides.
        // [SpecialName] (which manifests as MethodInfo.IsSpecialName) and [ImplicitConversionMethod] are not used in reflection when finding these methods.
        //
        [SpecialName, ImplicitConversionMethod]
		public static string ConvertToString( int x ) { return x.ToString(); }

        [SpecialName, ImplicitConversionMethod]
        public static bool ConvertToBoolean(int x) { return x != 0; }

        [SpecialName, ImplicitConversionMethod]
        public static int ConvertToInt32(bool x) { return x ? 1 : 0; }

        //
        // Operation nethod names are alternate operation names from the table built in Codeplex-DLR-1.0\Src\Runtime\Microsoft.Dynamic\Actions\OperatorInfo.cs
        // and are based in turn on guidelines at http://msdn2.microsoft.com/en-us/library/2sk3x8a7(vs.71).aspx 
        // DefaultBinder.DoOperation looks first for the main name (e.g. op_addition) on the target type (e.g. Int32) and then the extension types.
        // For Int32, these are Int32Ops and DecimalOps (as specified in ExcelBinder's static constructor).  Then, if no method is found, the search is
        // repeated with the alternate name (e.g Add), and the methods below are found.  As above, ActionBinder.GetMethod is used to perform the search.
        // [SpecialName] is not used in reflection when finding these methods.
        //
        [SpecialName]
		public static object Add( int x, int y )
		{
			long num = (long)x + (long)y;

			return ( ( -2147483648L <= num ) && ( num <= 0x7fffffffL ) )
				? (int)num
				: BigIntOps.Add( x, y );
		}

		[SpecialName]
		public static object Subtract( int x, int y )
		{
			long num = (long)x - (long)y;

			return ( ( -2147483648L <= num ) && ( num <= 0x7fffffffL ) )
				? (int)num
				: BigIntOps.Subtract( x, y );
		}

		[SpecialName]
		public static object Multiply( int x, int y )
		{
			long num = (long)x * (long)y;

			return ( ( -2147483648L <= num ) && ( num <= 0x7fffffffL ) )
				? (int)num
				: BigIntOps.Multiply( x, y );
		}

		[SpecialName]
		public static object Divide( int x, int y ) { return DoubleOps.Divide( x, y ); }

		[SpecialName]
		public static bool Equals( int x, int y ) { return ( x == y ); }
		[SpecialName]
		public static bool GreaterThan( int x, int y ) { return ( x > y ); }
		[SpecialName]
		public static bool GreaterThanOrEqual( int x, int y ) { return ( x >= y ); }
		[SpecialName]
		public static bool LessThan( int x, int y ) { return ( x < y ); }
		[SpecialName]
		public static bool LessThanOrEqual( int x, int y ) { return ( x <= y ); }
		[SpecialName]
		public static bool NotEquals( int x, int y ) { return ( x != y ); }
	}
}